package com.yzt.base.controller;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.WebAttributes;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import com.alibaba.fastjson.JSON;
import com.yzt.base.dto.MenuDto;
import com.yzt.base.entity.BaseUser;
import com.yzt.base.kit.Base;
import com.yzt.base.utils.RequestUtil;
import com.yzt.sys.entity.Permission;
import com.yzt.sys.entity.Role;
import com.yzt.sys.service.IMenuService;
import com.yzt.sys.service.IPermissionService;
import com.yzt.sys.service.IRoleMenuService;
import com.yzt.sys.service.IRoleService;
import com.yzt.sys.service.IUserRoleService;

import io.swagger.annotations.ApiOperation;

@Controller
public class BaseController {

	@Autowired
	private IMenuService menuService;
	@Autowired
	private IRoleService roleService;
	@Autowired
	private IRoleMenuService roleMenuService;
	@Autowired
	private IUserRoleService userRoleService;
	@Autowired
	private IPermissionService permissionService;

	@RequestMapping("/")
	public String main() {
		return "main";
	}

	@RequestMapping("/index")
	public String index() {
		return "index/index";
	}

	@RequestMapping("/user_login")
	public String loginPage() {
		return "login";
	}

	@RequestMapping("/login_fail")
	public String failure(HttpServletRequest request, Model model) {
		System.out.println(request.getSession().getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION));
		AuthenticationException exception = (AuthenticationException) request.getSession()
				.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
		String error;
		Throwable cause = exception.getCause();
		if (exception instanceof UsernameNotFoundException || cause instanceof BadCredentialsException) {
			error = "用户名或密码错误";
		} else if (cause instanceof DisabledException) {
			error = "账户已禁用";
		} else if (cause instanceof LockedException) {
			error = "账户已锁定";
		} else if (cause instanceof AccountExpiredException) {
			error = "账户已过期";
		} else if (cause instanceof CredentialsExpiredException) {
			error = "证书已过期";
		} else {
			error = "登录失败";
		}
		model.addAttribute("error", error);
		return "login";
	}

	@RequestMapping("/401")
	public String page_401() {
		return "error/401";
	}

	@RequestMapping("/404")
	public String page_404() {
		return "error/404";
	}

	@RequestMapping("/accessError")
	@ResponseStatus(code = HttpStatus.UNAUTHORIZED)
	public void accessError(HttpServletRequest request, HttpServletResponse response) throws Exception {
		boolean isAjax = RequestUtil.isAjax(request);
		if (isAjax) {
			response.setCharacterEncoding("UTF-8");
			response.setContentType("text/html;charset=UTF-8");
			PrintWriter out = response.getWriter();
			out.print(JSON.toJSONString(Base.fail(401, "无权限访问")));
		} else {
			response.sendRedirect("/401");
		}
	}

	@PostMapping("refreshMenu")
	@ResponseBody
	@ApiOperation("刷新认证信息")
	public Base<Object> refreshMenu() {
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
		Object principal = auth.getPrincipal();
		if (principal instanceof BaseUser) {
			BaseUser user = (BaseUser) principal;

			List<Role> roleList = roleService.list();// 获取所有角色信息列表
			List<Long> roleIds = roleList.stream().map(Role::getId).collect(Collectors.toList());
			List<Long> menuIds = roleMenuService.getMenuIdList(roleIds);// 获取所有拥有的菜单ID
			List<MenuDto> menuDtos = menuService.getMenuDtoList(menuIds); // 获取所有菜单信息

			user.setMenuList(menuDtos);
			UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user,
					auth.getCredentials(), auth.getAuthorities());
			SecurityContextHolder.getContext().setAuthentication(token);
			return Base.ok("用户菜单刷新成功");
		}

		return Base.fail("用户菜单刷新失败");
	}

	@PostMapping("refreshPermission")
	@ResponseBody
	@ApiOperation("刷新认证信息")
	public Base<Object> refreshPermission() {
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
		Object principal = auth.getPrincipal();
		if (principal instanceof BaseUser) {
			BaseUser user = (BaseUser) principal;

			List<GrantedAuthority> list = new ArrayList<>();

			List<Long> roleIds = userRoleService.getRoleIds(user.getId());

			List<Role> roleList = roleService.roleList(roleIds);// 获取所有角色信息列表
			for (Role role : roleList) {
				SimpleGrantedAuthority sauth = new SimpleGrantedAuthority("ROLE_" + role.getKeyword());
				list.add(sauth);
			}
			List<Permission> permissionList = permissionService.getPermissions(roleIds);
			for (Permission p : permissionList) {
				SimpleGrantedAuthority sauth = new SimpleGrantedAuthority(p.getKeyword());
				list.add(sauth);
			}

			UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user,
					auth.getCredentials(), list);
			SecurityContextHolder.getContext().setAuthentication(token);
			return Base.ok("用户权限刷新成功");
		}

		return Base.fail("用户权限刷新失败");
	}
}
